#pragma once

namespace gtl
{
	
class mem_file
{
public:
	enum seek_mode { seek_begin = SEEK_SET, seek_curr = SEEK_CUR, seek_end = SEEK_END, };

public:
	mem_file(size_t size = 0)
	{
		m_data = NULL;
		m_size = size;
		m_offset = 0;
		m_attached = false;
		if(size > 0)
			m_data = realloc(m_data, size);
	}

	mem_file(char* data, size_t size)
	{
		attach(data, size);
	}

	~mem_file()
	{
		if(!m_attached && m_data != NULL)
			free(m_data);
	}

public:
	void attach(char* data, size_t size)
	{
		m_data = data;
		m_size = size;
		m_offset = 0;
		m_attached = true;
	}

	size_t length()
	{
		return m_size;
	}

	size_t size()
	{
		return m_size;
	}

	size_t tell()
	{
		return m_offset;
	}

	int seek(int offset, int mode)
	{
		if(m_data == NULL || m_size == 0)
			return -1;

		int offst = m_offset;
		if(mode == seek_begin && offset < 0)
		{
			m_offset = 0;
			return offst;
		}

		if(mode == seek_end && offset > 0)
		{
			m_offset = m_size - 1;
			return offst;
		}

		if(mode == seek_curr && m_offset + offset + 1 >= m_size)
		{
			m_offset = m_size - 1;
			return offst;
		}

		if(mode == seek_curr && m_offset + offset < 0)
		{
			m_offset = 0;
			return offst;
		}

		if(mode == seek_begin)
			m_offset = offset;
		else if(mode == seek_curr)
			m_offset += offset;
		else if(mode == seek_end)
			m_offset = m_size - offset - 1;

		return offst;
	}

	template<class T>
	size_t read(T* buf, size_t len)
	{
		if(m_data == NULL || m_size == 0)
			return 0;

		size_t sz = min(len * sizeof(T), m_size - m_offset);
		if(sz == 0)
			return 0;

		memcpy(buf, m_data, sz);
		return sz;
	}

	template<class T>
	size_t write(T& buf)
	{
		if(m_data == NULL || m_size == 0)
			return 0;

		size_t sz = min(len * sizeof(T), m_size - m_offset);
		memcpy(m_data, buf, sz);
		return sz;
	}

	bool eof()
	{
		return m_offset == m_size;
	}

public:
	operator char*()
	{
		return m_data;
	}

	operator const char*() const
	{
		return m_data;
	}

protected:
	char* m_data;
	size_t m_size;
	size_t m_offset;
	bool m_attached;
};

} // end of namespace gtl